home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / games / 111 / movem.c < prev    next >
C/C++ Source or Header  |  1987-02-19  |  10KB  |  313 lines

  1. /*
  2.  *    movem.c (move monster)        Larn is copyrighted 1986 by Noah Morgan.
  3.  *
  4.  *    Here are the functions in this file:
  5.  *
  6.  *    movemonst()        Routine to move the monsters toward the player
  7.  *    movemt(x,y)        Function to move a monster at (x,y) -- must determine where
  8.  *    mmove(x,y,xd,yd)    Function to actually perform the monster movement
  9.  *    movsphere()         Function to look for and move spheres of annihilation
  10.  */
  11. #include "header.h"
  12.  
  13. /*
  14.  *    movemonst()        Routine to move the monsters toward the player
  15.  *
  16.  *    This routine has the responsibility to determine which monsters are to
  17.  *    move, and call movemt() to do the move.
  18.  *    Returns no value.
  19.  */
  20. static short w1[9],w1x[9],w1y[9];
  21. static int tmp1,tmp2,tmp3,tmp4,distance;
  22. movemonst()
  23.     {
  24.     register int i,j;
  25.     if (c[TIMESTOP]) return;    /* no action if time is stopped */
  26.     if (c[HASTESELF])  if ((c[HASTESELF]&1)==0)  return;
  27.     if (spheres) movsphere();    /* move the spheres of annihilation if any */
  28.     if (c[HOLDMONST])  return;    /* no action if monsters are held */
  29.  
  30.     if (c[AGGRAVATE])    /* determine window of monsters to move */
  31.       {
  32.       tmp1=playery-5; tmp2=playery+6; tmp3=playerx-10; tmp4=playerx+11;
  33.       distance=40; /* depth of intelligent monster movement */
  34.       }
  35.     else
  36.       {
  37.       tmp1=playery-3; tmp2=playery+4; tmp3=playerx-5; tmp4=playerx+6;
  38.       distance=17; /* depth of intelligent monster movement */
  39.       }
  40.  
  41.     if (level == 0) /* if on outside level monsters can move in perimeter */
  42.         {
  43.         if (tmp1 < 0) tmp1=0;         if (tmp2 > MAXY) tmp2=MAXY;
  44.         if (tmp3 < 0) tmp3=0;         if (tmp4 > MAXX) tmp4=MAXX;
  45.         }
  46.     else /* if in a dungeon monsters can't be on the perimeter (wall there) */
  47.         {
  48.         if (tmp1 < 1) tmp1=1;         if (tmp2 > MAXY-1) tmp2=MAXY-1;
  49.         if (tmp3 < 1) tmp3=1;         if (tmp4 > MAXX-1) tmp4=MAXX-1;
  50.         }
  51.  
  52.     for (j=tmp1; j<tmp2; j++) /* now reset monster moved flags */
  53.         for (i=tmp3; i<tmp4; i++)
  54.             moved[i][j] = 0;
  55.     moved[lasthx][lasthy]=0;
  56.  
  57.     if (c[AGGRAVATE] || !c[STEALTH]) /* who gets moved? split for efficiency */
  58.       {
  59.       for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
  60.         for (i=tmp3; i<tmp4; i++)
  61.           if (mitem[i][j])    /* if there is a monster to move */
  62.             if (moved[i][j]==0)    /* if it has not already been moved */
  63.               movemt(i,j);    /* go and move the monster */
  64.       }
  65.     else /* not aggravated and not stealth */
  66.       {
  67.       for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
  68.         for (i=tmp3; i<tmp4; i++)
  69.           if (mitem[i][j])    /* if there is a monster to move */
  70.             if (moved[i][j]==0)    /* if it has not already been moved */
  71.               if (stealth[i][j])    /* if it is asleep due to stealth */
  72.                 movemt(i,j);    /* go and move the monster */
  73.       }
  74.  
  75.     if (mitem[lasthx][lasthy]) /* now move monster last hit by player if not already moved */
  76.         {
  77.         if (moved[lasthx][lasthy]==0)    /* if it has not already been moved */
  78.             {
  79.             movemt(lasthx,lasthy);
  80.             lasthx = w1x[0];   lasthy = w1y[0];
  81.             }
  82.         }
  83.     }
  84.  
  85. /*
  86.  *    movemt(x,y)        Function to move a monster at (x,y) -- must determine where
  87.  *        int x,y;
  88.  *
  89.  *    This routine is responsible for determining where one monster at (x,y) will
  90.  *    move to.  Enter with the monsters coordinates in (x,y).
  91.  *    Returns no value.
  92.  */
  93. static int tmpitem,xl,xh,yl,yh;
  94. movemt(i,j)
  95.     int i,j;
  96.     {
  97.     register int k,m,z,tmp,xtmp,ytmp,monst;
  98.     switch(monst=mitem[i][j])  /* for half speed monsters */
  99.         {
  100.         case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
  101.         case INVISIBLESTALKER:  case ICELIZARD: if ((gtime & 1) == 1) return;
  102.         };
  103.  
  104.     if (c[SCAREMONST]) /* choose destination randomly if scared */
  105.         {
  106.         if ((xl = i+rnd(3)-2) < 0) xl=0;  if (xl >= MAXX) xl=MAXX-1;
  107.         if ((yl = j+rnd(3)-2) < 0) yl=0;  if (yl >= MAXY) yl=MAXY-1;
  108.         if ((tmp=item[xl][yl]) != OWALL)
  109.           if (mitem[xl][yl] == 0)
  110.             if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
  111.               if (tmp != OCLOSEDDOOR)        mmove(i,j,xl,yl);
  112.         return;
  113.         }
  114.  
  115.     if (monster[monst].intelligence > 10-c[HARDGAME]) /* if smart monster */
  116. /* intelligent movement here -- first setup screen array */
  117.       {
  118.       xl=tmp3-2; yl=tmp1-2; xh=tmp4+2;  yh=tmp2+2;
  119.       vxy(&xl,&yl);  vxy(&xh,&yh);
  120.       for (k=yl; k<yh; k++)
  121.         for (m=xl; m<xh; m++)
  122.           {
  123.           switch(item[m][k])
  124.             {
  125.               case OWALL: case OPIT: case OTRAPARROW: case ODARTRAP:
  126.             case OCLOSEDDOOR: case OTRAPDOOR: case OTELEPORTER:
  127.                 smm:      screen[m][k]=127;  break;
  128.             case OMIRROR: if (mitem[m][k]==VAMPIRE) goto smm;
  129.             default:  screen[m][k]=  0;  break;
  130.             };
  131.           }
  132.       screen[playerx][playery]=1;
  133.  
  134. /* now perform proximity ripple from playerx,playery to monster */
  135.       xl=tmp3-1; yl=tmp1-1; xh=tmp4+1;  yh=tmp2+1;
  136.       vxy(&xl,&yl);  vxy(&xh,&yh);
  137.       for (tmp=1; tmp<distance; tmp++)    /* only up to 20 squares away */
  138.         for (k=yl; k<yh; k++)
  139.           for (m=xl; m<xh; m++)
  140.             if (screen[m][k]==tmp) /* if find proximity n advance it */
  141.               for (z=1; z<9; z++) /* go around in a circle */
  142.                 {
  143.                 if (screen[xtmp=m+diroffx[z]][ytmp=k+diroffy[z]]==0)
  144.                   screen[xtmp][ytmp]=tmp+1;
  145.                 if (xtmp==i && ytmp==j) goto out;
  146.                 }
  147.  
  148. out:  if (tmp<distance) /* did find connectivity */
  149.         /* now select lowest value around playerx,playery */
  150.         for (z=1; z<9; z++) /* go around in a circle */
  151.           if (screen[xl=i+diroffx[z]][yl=j+diroffy[z]]==tmp)
  152.             if (!mitem[xl][yl]) { mmove(i,j,w1x[0]=xl,w1y[0]=yl); return; }
  153.       }
  154.  
  155.     /* dumb monsters move here */
  156.     xl=i-1;  yl=j-1;  xh=i+2;  yh=j+2;
  157.     if (i<playerx) xl++; else if (i>playerx) --xh;
  158.     if (j<playery) yl++; else if (j>playery) --yh;
  159.     for (k=0; k<9; k++) w1[k] = 10000;
  160.  
  161.     for (k=xl; k<xh; k++)
  162.         for (m=yl; m<yh; m++) /* for each square compute distance to player */
  163.             {
  164.             tmp = k-i+4+3*(m-j);
  165.             tmpitem = item[k][m];
  166.             if (tmpitem!=OWALL || (k==playerx && m==playery))
  167.              if (mitem[k][m]==0)
  168.               if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
  169.                  if (tmpitem!=OCLOSEDDOOR)
  170.                     {
  171.                     w1[tmp] = (playerx-k)*(playerx-k)+(playery-m)*(playery-m);
  172.                     w1x[tmp] = k;  w1y[tmp] = m;
  173.                     }
  174.             }
  175.  
  176.     tmp = 0;
  177.     for (k=1; k<9; k++)  if (w1[tmp] > w1[k])  tmp=k;
  178.  
  179.     if (w1[tmp] < 10000)
  180.         if ((i!=w1x[tmp]) || (j!=w1y[tmp]))
  181.             mmove(i,j,w1x[tmp],w1y[tmp]);
  182.     }
  183.  
  184. /*
  185.  *    mmove(x,y,xd,yd)    Function to actually perform the monster movement
  186.  *        int x,y,xd,yd;
  187.  *
  188.  *    Enter with the from coordinates in (x,y) and the destination coordinates
  189.  *    in (xd,yd).
  190.  */
  191. mmove(aa,bb,cc,dd)
  192.     int aa,bb,cc,dd;
  193.     {
  194.     register int tmp,i,flag;
  195.     char *who,*p;
  196.     flag=0;    /* set to 1 if monster hit by arrow trap */
  197.     if ((cc==playerx) && (dd==playery))
  198.         {
  199.         hitplayer(aa,bb);  moved[aa][bb] = 1;  return;
  200.         }
  201.     i=item[cc][dd];
  202.     if ((i==OPIT) || (i==OTRAPDOOR))
  203.       switch(mitem[aa][bb])
  204.         {
  205.         case SPIRITNAGA:    case PLATINUMDRAGON:    case WRAITH:
  206.         case VAMPIRE:        case SILVERDRAGON:        case POLTERGEIST:
  207.         case DEMONLORD:        case DEMONLORD+1:        case DEMONLORD+2:
  208.         case DEMONLORD+3:    case DEMONLORD+4:        case DEMONLORD+5:
  209.         case DEMONLORD+6:    case DEMONPRINCE:    break;
  210.  
  211.         default:    mitem[aa][bb]=0; /* fell in a pit or trapdoor */
  212.         };
  213.     tmp = mitem[cc][dd] = mitem[aa][bb];
  214.     if (i==OANNIHILATION)
  215.         {
  216.         if (tmp>=DEMONLORD+3) /* demons dispel spheres */
  217.             {
  218.             cursors();
  219.             lprintf("\nThe %s dispels the sphere!",monster[tmp].name);
  220.             rmsphere(cc,dd);    /* delete the sphere */
  221.             }
  222.         else i=tmp=mitem[cc][dd]=0;
  223.         }
  224.     stealth[cc][dd]=1;
  225.     if ((hitp[cc][dd] = hitp[aa][bb]) < 0) hitp[cc][dd]=1;
  226.     mitem[aa][bb] = 0;                moved[cc][dd] = 1;
  227.     if (tmp == LEPRECHAUN)
  228.         switch(i)
  229.             {
  230.             case OGOLDPILE:  case OMAXGOLD:  case OKGOLD:  case ODGOLD:
  231.             case ODIAMOND:   case ORUBY:     case OEMERALD: case OSAPPHIRE:
  232.                     item[cc][dd] = 0; /* leprechaun takes gold */
  233.             };
  234.  
  235.     if (tmp == TROLL)  /* if a troll regenerate him */
  236.         if ((gtime & 1) == 0)
  237.             if (monster[tmp].hitpoints > hitp[cc][dd])  hitp[cc][dd]++;
  238.  
  239.     if (i==OTRAPARROW)    /* arrow hits monster */
  240.         { who = "An arrow";  if ((hitp[cc][dd] -= rnd(10)+level) <= 0)
  241.             { mitem[cc][dd]=0;  flag=2; } else flag=1; }
  242.     if (i==ODARTRAP)    /* dart hits monster */
  243.         { who = "A dart";  if ((hitp[cc][dd] -= rnd(6)) <= 0)
  244.             { mitem[cc][dd]=0;  flag=2; } else flag=1; }
  245.     if (i==OTELEPORTER)    /* monster hits teleport trap */
  246.         { flag=3; fillmonst(mitem[cc][dd]);  mitem[cc][dd]=0; }
  247.     if (c[BLINDCOUNT]) return;    /* if blind don't show where monsters are    */
  248.     if (know[cc][dd] & 1) 
  249.         {
  250.         p=0;
  251.         if (flag) cursors();
  252.         switch(flag)
  253.           {
  254.           case 1: p="\n%s hits the %s";  break;
  255.           case 2: p="\n%s hits and kills the %s";  break;
  256.           case 3: p="\nThe %s%s gets teleported"; who="";  break;
  257.           };
  258.         if (p) { lprintf(p,who,monster[tmp].name); beep(); }
  259.         }
  260. /*    if (yrepcount>1) { know[aa][bb] &= 2;  know[cc][dd] &= 2; return; } */
  261.     if (know[aa][bb] & 1)   show1cell(aa,bb);
  262.     if (know[cc][dd] & 1)   show1cell(cc,dd);
  263.     }
  264.  
  265. /*
  266.  *    movsphere()     Function to look for and move spheres of annihilation
  267.  *
  268.  *    This function works on the sphere linked list, first duplicating the list
  269.  *    (the act of moving changes the list), then processing each sphere in order
  270.  *    to move it.  They eat anything in their way, including stairs, volcanic
  271.  *    shafts, potions, etc, except for upper level demons, who can dispel
  272.  *    spheres.
  273.  *    No value is returned.
  274.  */
  275. #define SPHMAX 20    /* maximum number of spheres movsphere can handle */
  276. movsphere()
  277.     {
  278.     register int x,y,dir,len;
  279.     register struct sphere *sp,*sp2;
  280.     struct sphere sph[SPHMAX];
  281.  
  282.     /* first duplicate sphere list */
  283.     for (sp=0,x=0,sp2=spheres; sp2; sp2=sp2->p)    /* look through sphere list */
  284.       if (sp2->lev == level)    /* only if this level */
  285.         {
  286.         sph[x] = *sp2;    sph[x++].p = 0;  /* copy the struct */
  287.         if (x>1)  sph[x-2].p = &sph[x-1]; /* link pointers */
  288.         }
  289.     if (x) sp= sph;    /* if any spheres, point to them */
  290.         else return;    /* no spheres */
  291.  
  292.     for (sp=sph; sp; sp=sp->p)    /* look through sphere list */
  293.         {
  294.         x = sp->x;      y = sp->y;
  295.         if (item[x][y]!=OANNIHILATION) continue;    /* not really there */
  296.         if (--(sp->lifetime) < 0)    /* has sphere run out of gas? */
  297.             {
  298.             rmsphere(x,y); /* delete sphere */
  299.             continue;
  300.             }
  301.         switch(rnd((int)max(7,c[INTELLIGENCE]>>1))) /* time to move the sphere */
  302.             {
  303.             case 1:
  304.             case 2:        /* change direction to a random one */
  305.                         sp->dir = rnd(8);
  306.             default:    /* move in normal direction */
  307.                         dir = sp->dir;        len = sp->lifetime;
  308.                         rmsphere(x,y);
  309.                         newsphere(x+diroffx[dir],y+diroffy[dir],dir,len);
  310.             };
  311.         }
  312.     }
  313.